home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / tn3270 / hndkbd.c < prev    next >
Text File  |  1992-04-17  |  25KB  |  1,058 lines

  1. /*
  2.  *  tn3270 for the Macintosh Source Code
  3.  *  Brown University Computing and Information Services
  4.  *  Version 2.4d7  April, 1992
  5.  *  Copyright (c) 1988, 1989, 1990, 1991, 1992 by Brown University and by
  6.  *  Peter John DiCamillo.
  7.  *
  8.  *  Permission is granted to any individual or institution to use, copy,
  9.  *  or redistribute the binary version of this software and its
  10.  *  documentation provided this notice and the copyright notices are
  11.  *  retained.  Permission is granted to any individual or non-profit
  12.  *  institution to use, copy, modify, or redistribute the source files
  13.  *  of this software provided this notice and the copyright notices are
  14.  *  retained.  This software may not be distributed for profit, either
  15.  *  in original form or in derivative works, nor can the source be
  16.  *  distributed to other than an individual or a non-profit institution.
  17.  *  Any  individual or group interested in seeing and/or using these
  18.  *  source files but who are prevented from doing so by the above
  19.  *  constraints should contact Don Wolfe, Assistant Vice-President for
  20.  *  Computer Systems at Brown University, (401) 863-7250, for possible
  21.  *  software licensing of the source developed at Brown.
  22.  *
  23.  *  Brown University and Peter John DiCamillo make no representations
  24.  *  about the suitability of this software for any purpose.
  25.  *
  26.  *  BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
  27.  *  EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  28.  *  INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  29.  *  WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  30.  *
  31.  */
  32.  
  33. #if !defined(USEDUMP)
  34.     #include "maclib.h"
  35.     #include "termdef.h"
  36.     #include "tn3270funcs.h"
  37.     #include "globals.h"
  38. #else
  39.     #pragma load "tn3270DumpFile"
  40. #endif
  41.  
  42. #pragma segment 3270seg2
  43.  
  44. #define    IAC    255        /* interpret as command: */
  45. #define EOR 239     /* end of record (transparent mode) */
  46.  
  47.  
  48. void hndkbd(unsigned char chr, unsigned char shift, cnr *cp)
  49. {
  50. register unsigned char c;
  51. register unsigned char typ, val, geflag, alphaflag;
  52. char paste;
  53.  
  54. c = chr;                /* get character */
  55.  
  56.             /* define type, value, and geflag for key */
  57. typ = kbtyp[c];
  58. alphaflag = geflag = 0;
  59. if (typ & 0x80) geflag = 1;
  60. if (typ & 0x40) alphaflag = 1;
  61. typ &= 0x3f;
  62. if (cp->aplmode) val = kbapl[c];
  63.     else {
  64.         val = kbstd[c];
  65.         if ((val == 0xad) || (val == 0xbd)) geflag = 1;
  66.         else geflag = 0;
  67.         }
  68.  
  69.             /* check if key should be ignored */
  70. if (val == 0) return;
  71.  
  72.             /* check for pasted character */
  73. if (shift == 99) {
  74.     shift = 0;
  75.     paste = 1;
  76.     }
  77. else {
  78.     paste = 0;
  79.     }
  80.  
  81.              /* check if alpa lock needs to be applied */
  82. if (alphaflag && shift) val += 0x40;
  83.  
  84.             /* process key based on type code */
  85.  
  86. switch(typ) {
  87.     case 1: datakey(val, geflag, paste, cp);
  88.         break;
  89.  
  90.     case 2: attnkey(val, paste, cp);
  91.         break;
  92.  
  93.     case 3: funckey(val, paste, cp);
  94.         break;
  95.  
  96.     default: break;
  97.     }
  98. }
  99.  
  100. void datakey(unsigned char val, unsigned char geflag, char paste, cnr *cp)
  101. {
  102. register short attroff;
  103. register short newattr;
  104. register short i;
  105. register unsigned char inpskip;
  106.  
  107. if (!cp->fmtscrn) {                /* unformatted screen */
  108.     if (cp->insmode || cp->inschar) if (cinsert(cp)) {  /* if insert, make room */
  109.             kerr(1, cp);
  110.             if (paste) cp->pastebeep = 1;    /* error if no room */
  111.             else beep(cp);
  112.             cp->apikberr = sendInsErr;
  113.             return;
  114.             }
  115.     newattr = (cp->atrbuff)[cp->curadr] & 0xbf00;
  116.     if (geflag) newattr |= 0x4000;
  117.     newchar(cp->curadr, val, newattr, 0, cp);
  118.     if (!paste) newwrite(cp);
  119.     cp->curadr++;
  120.     if (cp->curadr == cp->maxcnt) cp->curadr = 0;
  121.     if (!paste) newcur(cp);
  122.     kerr(0, cp);
  123.     return;
  124.     }
  125.                     /* else formatted screen */
  126. if ((cp->atrbuff)[cp->curadr] & 0x8000) {        /* cursor on attribute byte */
  127.     kerr(2, cp);
  128.     if (paste) cp->pastebeep = 1;
  129.     else beep(cp);
  130.     cp->apikberr = sendAttrErr;
  131.     return;
  132.     }
  133. attroff = getattr(cp->curadr, cp);
  134. if ((cp->atrbuff)[attroff] & 0x2000) {            /* protected */
  135.     kerr(2, cp);
  136.     if (paste) cp->pastebeep = 1;
  137.     else beep(cp);
  138.     cp->apikberr = sendProtErr;
  139.     return;
  140.     }
  141. if (cp->insmode || cp->inschar) if (cinsert(cp)) {    /* if insert, make room */
  142.         kerr(1, cp);
  143.         if (paste) cp->pastebeep = 1;        /* error if no room */
  144.         else beep(cp);
  145.         cp->apikberr = sendInsErr;
  146.         return;
  147.         }
  148. newattr = (cp->atrbuff)[cp->curadr] & 0xbf00; /* update buffer and display */
  149. if (geflag) newattr |= 0x4000;
  150. newchar(cp->curadr, val, newattr, (cp->atrbuff)[attroff], cp);
  151. if (!paste) newwrite(cp);
  152. (cp->atrbuff)[attroff] |= 0x0100;        /* set MDT bit */
  153. inpskip = 0;
  154. for (i=0; i < cp->maxcnt; i++) {        /* find next character position */
  155.     cp->curadr++;
  156.     if (cp->curadr == cp->maxcnt) cp->curadr = 0;
  157.     if ((cp->atrbuff)[cp->curadr] & 0x8000) {
  158.         /* after auto-skip, must find next unprotected field */
  159.         if (inpskip) inpskip = ((cp->atrbuff)[cp->curadr] & 0x2000) != 0;
  160.                 else inpskip = ((cp->atrbuff)[cp->curadr] & 0x3000) == 0x3000;
  161.         continue;
  162.         }
  163.     if (inpskip == 0) break;
  164.     }
  165. if (!paste) newcur(cp);
  166. kerr(0, cp);
  167. }
  168.  
  169. void attnkey(unsigned char val, char paste, cnr *cp)
  170. {
  171. short attroff, i;
  172.  
  173. cp->rdaid = val;            /* save aid code for read buffer */
  174.  
  175. if ((val >= 0x6b) && (val <= 0x6e)) {    /* handle short read */
  176.     if (val == 0x6d) {        /* CLEAR erases screen */
  177.         clrscn(cp);
  178.         invldscr(cp);
  179.         }
  180.     if (cp->insmode && cp->cs.insreset) {
  181.         cp->insmode = 0;
  182.         newstat(cp);
  183.         }
  184.     cp->readbuff[0] = 0xd7;
  185.     cp->readbuff[5] = val;
  186.     cp->rbsize = 6;
  187.     if (cp->tcpflg) {
  188.         cp->readbuff[cp->rbsize++] = IAC;
  189.         cp->readbuff[cp->rbsize++] = EOR;
  190.         }
  191.     senddata(1, cp);
  192.     return;
  193.     }
  194.  
  195. if (val == 0xf0) {            /* test request read */
  196.     if (cp->insmode && cp->cs.insreset) {
  197.         cp->insmode = 0;
  198.         newstat(cp);
  199.         }
  200.     cp->readbuff[0] = 0xd7;
  201.     cp->readbuff[5] = 0x01;
  202.     cp->readbuff[6] = 0x6c;
  203.     cp->readbuff[7] = 0x61;
  204.     cp->readbuff[8] = 0x02;
  205.     cp->rbsize = 9;
  206.     rdmod(0, cp);        /* append modified data */
  207.     return;
  208.     }
  209.  
  210. if (val == 0x7e) {            /* cursor select */
  211.     if (!cp->fmtscrn) {
  212.         kerr(2, cp);
  213.         if (paste) cp->pastebeep = 1;
  214.         else beep(cp);
  215.         cp->apikberr = sendAIDErr;
  216.         return;
  217.         }
  218.     attroff = getattr(cp->curadr, cp);
  219.     i = (cp->atrbuff)[attroff] & 0x0c00;
  220.     if ((i == 0) || (i == 0x0c00)) {
  221.         kerr(2, cp);
  222.         if (paste) cp->pastebeep = 1;
  223.         else beep(cp);
  224.         cp->apikberr = sendAIDErr;
  225.         return;
  226.         }
  227.     i = attroff + 1;
  228.     if (i == cp->maxcnt) {
  229.         kerr(2, cp);
  230.         if (paste) cp->pastebeep = 1;
  231.         else beep(cp);
  232.         cp->apikberr = sendAIDErr;
  233.         return;
  234.         }
  235.     switch((cp->chrbuff)[i]) {
  236.         case 0x00:            /* space and null */
  237.         case 0x40:    
  238.                 break;
  239.  
  240.         case 0x50:            /* ampersand */
  241.                 val = 0x7d;
  242.                 break;
  243.  
  244.         case 0x6f:            /* question mark */
  245.                 newchar(i, 0x6e, (cp->atrbuff)[i] & 0xbf00,  
  246.                         (cp->atrbuff)[attroff], cp);
  247.                 newwrite(cp);
  248.                 (cp->atrbuff)[attroff] |= 0x0100;    /* set MDT */
  249.                 kerr(0, cp);
  250.                 return;
  251.  
  252.         case 0x6e:            /* greater than */
  253.                 newchar(i, 0x6f, (cp->atrbuff)[i] & 0xbf00,
  254.                         (cp->atrbuff)[attroff], cp);
  255.                 newwrite(cp);
  256.                 (cp->atrbuff)[attroff] &= 0xfeff;    /* reset MDT */
  257.                 kerr(0, cp);
  258.                 return;
  259.  
  260.         default:    
  261.                 kerr(2, cp);
  262.                 if (paste) cp->pastebeep = 1;
  263.                 else beep(cp);
  264.                 cp->apikberr = sendAIDErr;
  265.                 return;
  266.         }
  267.     kerr(0, cp);
  268.     }
  269.  
  270.                     /* normal read-modified */
  271. if (cp->insmode && cp->cs.insreset) {
  272.     cp->insmode = 0;
  273.     newstat(cp);
  274.     }
  275.  
  276. rdmcmd(val, cp);
  277. }
  278.  
  279. void rdmcmd(unsigned char val, cnr *cp)            /* read-modified issued */
  280. {
  281. char lp_read;
  282. unsigned char addrbuff[2];
  283. short copylen;
  284.  
  285. lp_read = (val == 0x7e);
  286. cp->readbuff[0] = 0xd7;
  287. cp->readbuff[5] = val;
  288. cp->rbsize = 6;
  289. if ((val == IAC) && cp->tcpflg) {
  290.     cp->readbuff[cp->rbsize++] = IAC;
  291.     }
  292.                         /* append two-byte cursor address */
  293. ebcaddr(addrbuff, cp->curadr, cp);
  294. copylen = 2;
  295. tcpmemcpy(cp->readbuff+cp->rbsize, addrbuff, ©len, cp->tcpflg);
  296. cp->rbsize += copylen;        /* append modified data */
  297. rdmod(lp_read, cp);
  298. }
  299.  
  300. void rdmacmd(unsigned char val, cnr *cp)        /* read-modified all issued */
  301. {
  302. unsigned char addrbuff[2];
  303. short copylen;
  304.  
  305. cp->readbuff[0] = 0xd7;
  306. cp->readbuff[5] = val;
  307. cp->rbsize = 6;
  308. if ((val == IAC) && cp->tcpflg) {
  309.     cp->readbuff[cp->rbsize++] = IAC;
  310.     }
  311.             /* append two-byte cursor address */
  312. ebcaddr(addrbuff, cp->curadr, cp);
  313. copylen = 2;
  314. tcpmemcpy(cp->readbuff+cp->rbsize, addrbuff, ©len, cp->tcpflg);
  315. cp->rbsize += copylen;        /* append modified data */
  316. rdmod(0, cp);
  317. }
  318.  
  319. void funckey(unsigned char val, char paste, cnr *cp)
  320. {
  321. register unsigned char prot;
  322. register short a, attroff, b, chroff, i, next;
  323.  
  324. switch(val) {
  325.  
  326. case 1: cp->curadr -= cp->scrhsize;            /* up */
  327.     if (cp->curadr < 0) cp->curadr += cp->maxcnt;
  328.     newcur(cp);
  329.     break;
  330.  
  331. case 2: cp->curadr += cp->scrhsize;            /* down */
  332.     if (cp->curadr > cp->maxoff) cp->curadr -= cp->maxcnt;
  333.     newcur(cp);
  334.     break;
  335.  
  336. case 3: cp->curadr--;                /* left */
  337.     if (cp->curadr < 0) cp->curadr = cp->maxoff;
  338.     newcur(cp);
  339.     break;
  340.  
  341. case 4: cp->curadr++;                /* right */
  342.     if (cp->curadr > cp->maxoff) cp->curadr = 0;
  343.     newcur(cp);
  344.     break;
  345.  
  346. case 5: if (!cp->fmtscrn) {                /* tab */
  347.         cp->curadr = 0;
  348.         newcur(cp);
  349.         return;
  350.         }
  351.     if ((cp->atrbuff)[cp->curadr] & 0x8000)        /* initial prot value */
  352.         prot = ((cp->atrbuff)[cp->curadr] & 0x2000) != 0;
  353.     else prot = 1;
  354.     a = cp->curadr + 1;
  355.     if (a == cp->maxcnt) a = 0;        /* loop from next position */
  356.     for (i=0; i < cp->maxcnt; i++) {
  357.         if ((cp->atrbuff)[a] & 0x8000)
  358.             prot = ((cp->atrbuff)[a] & 0x2000) != 0;
  359.         else if (!prot) {
  360.             cp->curadr = a;
  361.             newcur(cp);
  362.             return;
  363.             }
  364.         a++;
  365.         if (a == cp->maxcnt) a = 0;
  366.         }
  367.     cp->curadr = 0;
  368.     newcur(cp);
  369.     break;
  370.  
  371. case 6: if (!cp->fmtscrn) {                /* backtab */
  372.         cp->curadr = 0;
  373.         newcur(cp);
  374.         return;
  375.         }
  376.     a = cp->curadr - 1;            /* start at previous position */
  377.     if (a < 0) a = cp->maxoff;
  378.     chroff = -1;            /* no character yet */
  379.     for (i=0; i <= cp->maxcnt; i++) { /* find unprotected character */
  380.         if ((cp->atrbuff)[a] & 0x8000) {        /* attribute */
  381.             if ((cp->atrbuff)[a] & 0x2000) chroff = -1;
  382.             else if (chroff > 0) {
  383.                 cp->curadr = chroff;
  384.                 newcur(cp);
  385.                 return;
  386.                 }
  387.             }
  388.         else chroff = a;
  389.         a--;
  390.         if (a < 0) a = cp->maxoff;
  391.         }
  392.     cp->curadr = 0;
  393.     newcur(cp);
  394.     break;
  395.  
  396. case 7: if (!cp->fmtscrn) {                /* newline */
  397.         cp->curadr = ((cp->curadr / cp->scrhsize) + 1) * cp->scrhsize;
  398.         if (cp->curadr == cp->maxcnt) cp->curadr = 0;
  399.         newcur(cp);
  400.         return;
  401.         }
  402.     a = ((cp->curadr / cp->scrhsize) + 1) * cp->scrhsize;
  403.     if (a == cp->maxcnt) a = 0;
  404.     if (!((cp->atrbuff)[a] & 0x8000))        /* set prot for first char. */
  405.         prot = ((cp->atrbuff)[getattr(a, cp)] & 0x2000) != 0;
  406.     for (i=0; i < cp->maxcnt; i++) {
  407.         if ((cp->atrbuff)[a] & 0x8000) prot = ((cp->atrbuff)[a] & 0x2000) != 0;
  408.         else if (!prot) {
  409.             cp->curadr = a;
  410.             newcur(cp);
  411.             return;
  412.             }
  413.         a++;
  414.         if (a == cp->maxcnt) a = 0;
  415.         }
  416.     cp->curadr = 0;
  417.     newcur(cp);
  418.     break;
  419.  
  420. case 8: if (!cp->fmtscrn) {                /* home */
  421.         cp->curadr = 0;
  422.         newcur(cp);
  423.         return;
  424.         }
  425.     a = 0;
  426.     if (!((cp->atrbuff)[a] & 0x8000))        /* set prot for first char. */
  427.         prot = ((cp->atrbuff)[getattr(a, cp)] & 0x2000) != 0;
  428.     for (i=0; i < cp->maxcnt; i++) {
  429.         if ((cp->atrbuff)[a] & 0x8000) prot = ((cp->atrbuff)[a] & 0x2000) != 0;
  430.         else if (!prot) {
  431.             cp->curadr = a;
  432.             newcur(cp);
  433.             return;
  434.             }
  435.         a++;
  436.         if (a == cp->maxcnt) a = 0;
  437.         }
  438.     cp->curadr = 0;
  439.     newcur(cp);
  440.     break;
  441.  
  442. case 9:                        /* erase eof */
  443.     if (!cp->fmtscrn) {                /* unformatted screen */
  444.         for (a=cp->curadr; a < cp->maxcnt; a++) {
  445.             newchar(a, 0x00, 0, 0, cp);
  446.             }
  447.         newwrite(cp);
  448.         kerr(0, cp);
  449.         break;
  450.         }
  451.                                 /* else formatted screen */
  452.     if ((cp->atrbuff)[cp->curadr] & 0x8000) {        /* cursor on attribute byte */
  453.         kerr(2, cp);
  454.         if (paste) cp->pastebeep = 1;
  455.         else beep(cp);
  456.         cp->apikberr = sendAttrErr;
  457.         return;
  458.         }
  459.     attroff = getattr(cp->curadr, cp);
  460.     if ((cp->atrbuff)[attroff] & 0x2000) {    /* protected */
  461.         kerr(2, cp);
  462.         if (paste) cp->pastebeep = 1;
  463.         else beep(cp);
  464.         cp->apikberr = sendProtErr;
  465.         return;
  466.         }
  467.     a = cp->curadr;                /* loop to store nulls */
  468.     for (i=0; i < cp->maxcnt; i++) {
  469.         if ((cp->atrbuff)[a] & 0x8000) break;        /* stop at attribute */
  470.         newchar(a, 0x00, 0, (cp->atrbuff)[attroff], cp);
  471.         a++;
  472.         if (a == cp->maxcnt) a = 0;
  473.         }
  474.     newwrite(cp);
  475.     (cp->atrbuff)[attroff] |= 0x0100;        /* set MDT bit */
  476.     kerr(0, cp);
  477.     break;
  478.  
  479. case 10: if (!cp->fmtscrn) {            /* erase input */
  480.         clrscn(cp);
  481.         invldscr(cp);
  482.         return;
  483.         }
  484.     b = 9999;
  485.     a = firstattr(cp);                /* start at first attribute */
  486.     attroff = 0;
  487.     for (i=0; i < cp->maxcnt; i++) {
  488.         if ((cp->atrbuff)[a] & 0x8000) {        /* attribute */
  489.             prot = ((cp->atrbuff)[a] & 0x2000) != 0;
  490.             if (!prot) (cp->atrbuff)[a] &= 0xfeff;  /* reset MDT */
  491.             attroff = a;        /* save attribute offset */
  492.             }
  493.         else if (!prot) {            /* character */
  494.             newchar(a, 0x00, 0, (cp->atrbuff)[attroff], cp);
  495.             if (a < b) b = a;    /* save first character */
  496.             }
  497.         a++;
  498.         if (a == cp->maxcnt) a = 0;
  499.         }
  500.     newwrite(cp);
  501.     if (b < 9999) cp->curadr = b;
  502.         else cp->curadr = 0;
  503.     newcur(cp);
  504.     break;
  505.  
  506. case 11: cp->insmode ^= 1;                /* toggle insert mode */
  507.     newstat(cp);
  508.     break;
  509.  
  510. case 12: if (cp->fmtscrn) {                /* delete character */
  511.         if ((cp->atrbuff)[cp->curadr] & 0x8000) { /* cursor on attribute byte */
  512.             kerr(2, cp);
  513.             if (paste) cp->pastebeep = 1;
  514.             else beep(cp);
  515.             return;
  516.             }
  517.         i = (cp->atrbuff)[attroff = getattr(cp->curadr, cp)];
  518.         if (i & 0x2000) {    /* protected */
  519.             kerr(2, cp);
  520.             if (paste) cp->pastebeep = 1;
  521.             else beep(cp);
  522.             return;
  523.             }
  524.         }
  525.         else i = 0;
  526.     a = cp->curadr;            /* first location to change */
  527.                         /* calculate last location to change */
  528.     if (cp->cs.repnull && cp->fmtscrn) {    
  529.         if (a > 0) b = a - 1;
  530.         else b = cp->maxoff;
  531.         }
  532.     else {
  533.         b = ((cp->curadr / cp->scrhsize) + 1) * cp->scrhsize - 1;    /* last loc. on line */
  534.         }
  535.     while (a != b) {
  536.         next = a+1;
  537.         if (next == cp->maxcnt) next = 0;
  538.         if ((cp->atrbuff)[next] & 0x8000) break;
  539.         else {
  540.             newchar(a, (cp->chrbuff)[next], (cp->atrbuff)[next], i, cp);
  541.             a = next;
  542.             }
  543.         }
  544.     newchar(a, 0x00, 0, i, cp);
  545.     newwrite(cp);
  546.     if (cp->fmtscrn) (cp->atrbuff)[attroff] |= 0x0100;    /* set MDT bit */
  547.     kerr(0, cp);
  548.     break;
  549.  
  550. case 13: cp->kb_err = cp->kblock = cp->kblcode = cp->insmode = 0;    /* reset */
  551.         cp->kbqsize = 0;
  552.         newstat(cp);
  553.         break;
  554.  
  555. case 14: if (!cp->fmtscrn) {            /* dup */
  556.         if (cp->insmode) if (cinsert(cp)) {    /* if insert, make room */
  557.             kerr(1, cp);
  558.             if (paste) cp->pastebeep = 1;    /* error if no room */
  559.             else beep(cp);
  560.             return;
  561.             }
  562.         b = (cp->atrbuff)[cp->curadr] & 0xbf00;
  563.         newchar(cp->curadr, 0x1c, b, 0, cp);
  564.         newwrite(cp);
  565.         cp->curadr = 0;
  566.         newcur(cp);
  567.         kerr(0, cp);
  568.         return;
  569.         }
  570.                         /* else formatted screen */
  571.     if ((cp->atrbuff)[cp->curadr] & 0x8000) {        /* cursor on attribute byte */
  572.         kerr(2, cp);
  573.         if (paste) cp->pastebeep = 1;
  574.         else beep(cp);
  575.         return;
  576.         }
  577.     attroff = getattr(cp->curadr, cp);
  578.     if ((cp->atrbuff)[attroff] & 0x2000) {            /* protected */
  579.         kerr(2, cp);
  580.         if (paste) cp->pastebeep = 1;
  581.         else beep(cp);
  582.         return;
  583.         }
  584.     if (cp->insmode) if (cinsert(cp)) {        /* if insert, make room */
  585.             kerr(1, cp);
  586.             if (paste) cp->pastebeep = 1;    /* error if no room */
  587.             else beep(cp);
  588.             return;
  589.             }
  590.     b = (cp->atrbuff)[cp->curadr] & 0xbf00;        /* update buffer and display */
  591.     newchar(cp->curadr, 0x1c, b, (cp->atrbuff)[attroff], cp);
  592.     newwrite(cp);
  593.     (cp->atrbuff)[attroff] |= 0x0100;        /* set MDT bit */
  594.     kerr(0, cp);
  595.     prot = 1;
  596.     a = cp->curadr + 1;
  597.     if (a == cp->maxcnt) a = 0;        /* loop from next position */
  598.     for (i=0; i < cp->maxcnt; i++) {
  599.         if ((cp->atrbuff)[a] & 0x8000)
  600.             prot = ((cp->atrbuff)[a] & 0x2000) != 0;
  601.         else if (!prot) {
  602.             cp->curadr = a;
  603.             newcur(cp);
  604.             return;
  605.             }
  606.         a++;
  607.         if (a == cp->maxcnt) a = 0;
  608.         }
  609.     cp->curadr = 0;
  610.     newcur(cp);
  611.     break;
  612.  
  613. case 15: datakey(0x1e, 0, paste, cp);    /* field mark */
  614.     break;
  615.  
  616. case 16: cp->aplmode ^= 1;                /* toggle APL mode */
  617.     cp->fixbracket = cp->cs.std_brack && (!cp->aplmode) && (cp->stdfont != ALAFONT);
  618.     newstat(cp);
  619.     break;
  620.  
  621. case 17:                            /* insert blank */
  622.     a = cp->curadr;
  623.     cp->inschar = 1;
  624.     datakey(0x40, 0, paste, cp);
  625.     cp->inschar = 0;
  626.     cp->curadr = a;
  627.     newcur(cp);
  628.     break;
  629.  
  630. case 18:                            /* rub out (non-std) */
  631.     a = cp->curadr;                        /* get previous location */
  632.     a--;
  633.     if (a < 0) a = cp->maxoff;
  634.     if (cp->fmtscrn) {
  635.         if ((cp->atrbuff)[a] & 0x8000) {    /* attribute byte */
  636.             kerr(2, cp);
  637.             if (paste) cp->pastebeep = 1;
  638.             else beep(cp);
  639.             return;
  640.             }
  641.         attroff = getattr(a, cp);
  642.         if ((cp->atrbuff)[attroff] & 0x2000) {    /* protected */
  643.             kerr(2, cp);
  644.             if (paste) cp->pastebeep = 1;
  645.             else beep(cp);
  646.             return;
  647.             }
  648.         }
  649.     cp->curadr = a;
  650.     datakey(0x00, 0, paste, cp);
  651.     cp->curadr = a;
  652.     newcur(cp);
  653.     break;
  654.  
  655. case 19: cp->curadr -= cp->scrhsize * 2;    /* up*2 */
  656.     if (cp->curadr < 0) cp->curadr += cp->maxcnt;
  657.     newcur(cp);
  658.     break;
  659.  
  660. case 20: cp->curadr += cp->scrhsize * 2;    /* down */
  661.     if (cp->curadr > cp->maxoff) cp->curadr -= cp->maxcnt;
  662.     newcur(cp);
  663.     break;
  664.  
  665. case 21: cp->curadr-=2;                /* left */
  666.     if (cp->curadr < 0) cp->curadr += cp->maxcnt;
  667.     newcur(cp);
  668.     break;
  669.  
  670. case 22: cp->curadr+=2;                /* right */
  671.     if (cp->curadr > cp->maxoff) cp->curadr -=cp->maxcnt;
  672.     newcur(cp);
  673.     break;
  674.  
  675. case 23:    cp->cs.curpos ^= 1;        /* cursor position */
  676.             newstat(cp);
  677.             break;
  678.  
  679. default:    
  680.             cp->apikberr = sendOpErr;
  681.             break;
  682.     }
  683.  
  684. }
  685.  
  686. short getattr(short offset, cnr *cp)
  687. {
  688. register short i;
  689. short nextoffset;
  690.  
  691. /* just return result if already at an attribute */
  692. if ((cp->atrbuff)[offset] & 0x8000) {
  693.     cp->savedvalid = 1;
  694.     cp->savedoffset = offset;
  695.     cp->savedattr = offset;
  696.     return(offset);
  697.     }
  698.  
  699. /* check if we already know the result from the last time */
  700. if (cp->savedvalid) {
  701.     nextoffset = cp->savedoffset + 1;
  702.     if (nextoffset == cp->maxcnt) nextoffset = 0;
  703.     if (nextoffset == offset) {
  704.         cp->savedoffset = nextoffset;
  705.         return(cp->savedattr);
  706.         }
  707.     }
  708.  
  709. /* scan backwards to find the attribute */
  710.  
  711. if (offset == 0) offset = cp->maxoff;
  712.     else offset--;
  713. for (i=0; i < cp->maxoff; i++) {
  714.     if ((cp->atrbuff)[offset] & 0x8000) {
  715.         cp->savedvalid = 1;
  716.         cp->savedoffset = offset;
  717.         cp->savedattr = offset;
  718.         return(offset);
  719.         }
  720.     if (offset == 0) offset = cp->maxoff;
  721.         else offset--;
  722.     }
  723.  
  724. return(offset);     /* shouldn't be called this way */
  725. }
  726.  
  727. short firstattr(cnr *cp)
  728. {
  729. register short i;
  730. for (i=0; i < cp->maxcnt; i++) {
  731.     if ((cp->atrbuff)[i] & 0x8000) return(i);
  732.     }
  733.  
  734. return(0);    /* return 0 if no attributes (shouldn't be called this way) */
  735. }
  736.  
  737. void rdmod(char lp_read, cnr *cp)
  738. {
  739. register unsigned short i, offset, j, k;
  740. register unsigned char c, mod;
  741. char modwrap;        /* true if last modified field may wrap */
  742. unsigned char addrbuff[2];
  743. short copylen;
  744.  
  745. if (cp->cs.repnull) nullreplace(cp);
  746.  
  747. if (!cp->fmtscrn) {
  748.     for (i=0; i < cp->maxcnt; i++) {
  749.         if ((c = (cp->chrbuff)[i]) == 0) continue;
  750.         if (cp->rbsize > (cp->rballoc-4)) {
  751.             if (cp->tcpflg) {
  752.                 senddata(1, cp);
  753.                 cp->rbsize = 5;
  754.                 }
  755.             else {
  756.                 break;
  757.                 }
  758.             }
  759.         if ((cp->atrbuff)[i] & 0x4000) 
  760.             if (!(((c == 0xad) || (c == 0xbd)) && cp->fixbracket))
  761.                 cp->readbuff[cp->rbsize++] = 0x08;
  762.         cp->readbuff[cp->rbsize++] = c;
  763.         if ((c == IAC) && cp->tcpflg) {
  764.             cp->readbuff[cp->rbsize++] = IAC;
  765.             }
  766.         }
  767.     cp->bufadr = 0;
  768.     if (cp->tcpflg) addeor(cp);
  769.     senddata(1, cp);
  770.     return;
  771.     }
  772.  
  773. offset=firstattr(cp);
  774. for (i=0; i < cp->maxcnt; i++) {
  775.     k = (cp->atrbuff)[offset];
  776.     if (k & 0x8000) {        /* handle attribute byte */
  777.         mod = 0;
  778.         modwrap = 0;
  779.         if (k & 0x0100) {        /* MDT bit set */
  780.             if (!lp_read) {
  781.                 mod = 1;
  782.                 }
  783.             modwrap = 1;
  784.             j = offset+1;
  785.             if (j > cp->maxoff) j = 0;
  786.             if ((cp->rbsize > (cp->rballoc-6)) && cp->tcpflg) {
  787.                 senddata(1, cp);
  788.                 cp->rbsize = 5;
  789.                 }
  790.             if (cp->rbsize <= (cp->rballoc-6)) {
  791.                 cp->readbuff[cp->rbsize++] = 0x11;
  792.                 ebcaddr(addrbuff, j, cp);    /* store 2-byte address */
  793.                 copylen = 2;
  794.                 tcpmemcpy(cp->readbuff+cp->rbsize, addrbuff, ©len,
  795.                           cp->tcpflg);
  796.                 cp->rbsize += copylen;
  797.                 }
  798.             }
  799.         }
  800.     else if (mod) {            /* handle data byte in modified field */
  801.         if ((c = (cp->chrbuff)[offset]) != 0) {
  802.             if ((cp->rbsize > (cp->rballoc-4)) && cp->tcpflg) {
  803.                 senddata(1, cp);
  804.                 cp->rbsize = 5;
  805.                 }
  806.             if (cp->rbsize <= (cp->rballoc-4)) {
  807.                 if (k & 0x4000) {
  808.                     if (!(((c == 0xad) || (c == 0xbd)) && cp->fixbracket)) {
  809.                         cp->readbuff[cp->rbsize++] = 0x08;
  810.                         }
  811.                     }
  812.                 cp->readbuff[cp->rbsize++] = c;
  813.                 if ((c == IAC) && cp->tcpflg) {
  814.                     cp->readbuff[cp->rbsize++] = IAC;
  815.                     }
  816.                 }
  817.             }
  818.         }
  819.     offset++;
  820.     if (offset > cp->maxoff) offset = 0;
  821.     }
  822. cp->bufadr = 0;
  823. /* change buffer address if last modified field wraps */
  824. if (modwrap && (offset != 0)) cp->bufadr = offset;
  825.  
  826. if (cp->tcpflg) addeor(cp);
  827. senddata(1, cp);
  828. }
  829.  
  830. void rdbuff(cnr *cp)        /* read buffer */
  831. {
  832. register short i;
  833. register unsigned char c, atrbyte;
  834. unsigned char addrbuff[2];
  835. short copylen;
  836.  
  837. cp->readbuff[0] = 0xc2;
  838. cp->readbuff[5] = cp->rdaid;
  839. cp->rbsize = 6;
  840. if ((cp->rdaid == IAC) && cp->tcpflg) {
  841.     cp->readbuff[cp->rbsize++] = IAC;
  842.     }
  843.                         /* append two-byte cursor address */
  844. ebcaddr(addrbuff, cp->curadr, cp);
  845. copylen = 2;
  846. tcpmemcpy(cp->readbuff+cp->rbsize, addrbuff, ©len, cp->tcpflg);
  847. cp->rbsize += copylen;
  848.  
  849. if (cp->cs.repnull) nullreplace(cp);
  850.  
  851. for (i=0; i < cp->maxcnt; i++) {
  852.     if (cp->rbsize > (cp->rballoc-4)) {
  853.         if (cp->tcpflg) {
  854.             senddata(0, cp);
  855.             cp->rbsize = 5;
  856.             }
  857.         else {
  858.             break;
  859.             }
  860.         }
  861.     if ((cp->atrbuff)[i] & 0x8000) {    /* attribute byte */
  862.         cp->readbuff[cp->rbsize++] = 0x1d;    /* start field */
  863.         atrbyte = ((cp->atrbuff)[i] >> 8) & 0x3f;
  864.         cp->readbuff[cp->rbsize++] = ebc64[atrbyte];    /* attribute */
  865.         }
  866.     else {
  867.         c = (cp->chrbuff)[i];
  868.         if ((cp->atrbuff)[i] & 0x4000)
  869.             if (!(((c == 0xad) || (c == 0xbd)) && cp->fixbracket))
  870.                 cp->readbuff[cp->rbsize++] = 0x08;
  871.         cp->readbuff[cp->rbsize++] = c;
  872.         if ((c == IAC) && cp->tcpflg) {
  873.             cp->readbuff[cp->rbsize++] = IAC;
  874.             }
  875.         }
  876.     }
  877. cp->bufadr = 0;
  878. if (cp->tcpflg) addeor(cp);
  879. senddata(0, cp);
  880. }
  881.  
  882. void addeor(cnr *cp)
  883. {
  884. if (cp->rbsize > (cp->rballoc-3)) {
  885.     senddata(1, cp);
  886.     cp->rbsize = 5;
  887.     }
  888. cp->readbuff[cp->rbsize++] = IAC;
  889. cp->readbuff[cp->rbsize++] = EOR;
  890. }
  891.  
  892. short cinsert(cnr *cp)
  893. {
  894. register unsigned char t;
  895. register short a, b, c, i, n;
  896.  
  897. b = c = n = -1;            /* -1 = no blank, character or null found */
  898. a = cp->curadr;            /* scan to end of field or all bytes */
  899. for (i = 0; i < cp->maxcnt; i++) {
  900.     if ((cp->atrbuff)[a] & 0x8000) break;        /* stop at attribute byte */
  901.     t = (cp->chrbuff)[a];                /* get charcter value */
  902.                                 /* do null to blank conversion if wanted */
  903.     if ((t == 0x00) && cp->cs.repnull) t = 0x40;
  904.     if (t == 0x00) {            /* found null */
  905.         n = a;                /* remember where */
  906.         break;                /* done now */
  907.         }
  908.     if (t == 0x40) b = i;            /* remember last blank */
  909.     else c = i;                /* remember last character */
  910.     a++;
  911.     if (a == cp->maxcnt) a = 0;
  912.     }
  913.  
  914. if (n >= 0) a = n;            /* use null if found */
  915.     else if ((b > c) && cp->cs.impnull) {    /* else use trailing blank */
  916.         a = cp->curadr + b;                /* (non-standard */
  917.         if (a > cp->maxoff) a -= cp->maxcnt;
  918.         }
  919.         else return(1);        /* else return error */
  920.  
  921. if (cp->fmtscrn) i = (cp->atrbuff)[getattr(cp->curadr, cp)]; 
  922. else i = 0;
  923. while (a != cp->curadr) {            /* loop to shift bytes right */
  924.     b = a-1;            /* get previous offset */
  925.     if (b < 0) b = cp->maxoff;
  926.     newchar(a, (cp->chrbuff)[b], (cp->atrbuff)[b], i, cp); /* define new values */
  927.     a--;
  928.     if (a < 0) a = cp->maxoff;
  929.     }
  930. return(0);
  931. }
  932.  
  933. void nullreplace(cnr *cp)
  934. {
  935. register unsigned short i, offset, nullcount, a;
  936. register unsigned char mod;
  937. unsigned char *firstnull;
  938.  
  939. if (!cp->fmtscrn) {
  940.     nullcount = 0;
  941.     for (i=0; i < cp->maxcnt; i++) {
  942.         if ((cp->chrbuff)[i] == 0) {
  943.             if (nullcount == 0) firstnull = cp->chrbuff+i;
  944.             nullcount++;
  945.             }
  946.         else {
  947.             while (nullcount > 0) {
  948.                 (*firstnull) = 0x40;
  949.                 firstnull++;
  950.                 nullcount--;
  951.                 }
  952.             }
  953.         }
  954.     return;
  955.     }
  956.  
  957. offset=firstattr(cp);
  958. for (i=0; i < cp->maxcnt; i++) {
  959.     a = (cp->atrbuff)[offset];
  960.     if (a & 0x8000) {        /* handle attribute byte */
  961.         mod = 0;
  962.         if (a & 0x0100) {        /* MDT bit set */
  963.             mod = 1;
  964.             nullcount = 0;
  965.             }
  966.         }
  967.     else if (mod) {            /* handle data byte in modified field */
  968.         if ((cp->chrbuff)[offset] == 0) {
  969.             if (nullcount == 0) firstnull = cp->chrbuff+offset;
  970.             nullcount++;
  971.             }
  972.         else {
  973.             while (nullcount > 0) {
  974.                 (*firstnull) = 0x40;
  975.                 firstnull++;
  976.                 nullcount--;
  977.                 }
  978.             }
  979.         }
  980.     offset++;
  981.     if (offset > cp->maxoff) offset = 0;
  982.     }
  983. }
  984.  
  985. void senddata(char lockflag, cnr *cp)
  986. {
  987.  
  988. cp->kb_err = 0;
  989.  
  990. if (cp->tcpflg) {
  991.     if (lockflag) {
  992.         cp->kblock = 1;
  993.         cp->kblcode = 2;
  994.         }
  995.     tcpwrite(cp->readbuff+5, cp->rbsize-5, cp);
  996.     return;
  997.     }
  998.  
  999. if (cp->serflg) {
  1000.     cp->readbuff[1] = cp->readbuff[2] = 0;
  1001.     serattn(cp);
  1002.     if (lockflag) {
  1003.         cp->kblock = 1;
  1004.         cp->kblcode = 2;
  1005.         newstat(cp);
  1006.         }
  1007.     return;
  1008.     }
  1009.  
  1010. if (lockflag) {
  1011.     cp->kblock = 1;
  1012.     cp->kblcode = 2;
  1013.     }
  1014. sawrite(cp->readbuff+5, cp->rbsize-5, cp);
  1015. }
  1016.  
  1017. void kerr(short code, cnr *cp)
  1018. {
  1019. if (code == cp->kb_err) return;
  1020. cp->kb_err = code;
  1021. newstat(cp);
  1022. }
  1023.  
  1024. void kbnew(unsigned char chr, cnr *cp)
  1025. {
  1026. register unsigned char c, typ, val;
  1027.  
  1028.  
  1029. c = chr;                /* get character */
  1030.  
  1031.             /* define type, value for key */
  1032. typ = kbtyp[c] & 0x3f;
  1033. if (cp->aplmode) val = kbapl[c];
  1034.     else val = kbstd[c];
  1035.  
  1036.             /* check for Enter or CLEAR to start new session */
  1037. if ((typ == 2) && ((val == 0x6d) || (val == 0x7d))) {
  1038.     if (cp->serflg) serlgin(cp);
  1039.     else if (cp->tcpflg) tcplgin(cp);
  1040.     else salgin(cp);
  1041.     return;
  1042.     }
  1043. beep(cp);
  1044. }
  1045.  
  1046. void ebcaddr(unsigned char *buf, unsigned short addr, cnr *cp)
  1047. {
  1048. if (cp->addr14 && cp->ewamode) {    /* generate 14-bit address */
  1049.     buf[0] = addr/256;
  1050.     buf[0] &= 0x3f;
  1051.     buf[1] = addr%256;
  1052.     }
  1053. else {                        /* generate 12-bit address */
  1054.     buf[0] = ebc64[addr/64];
  1055.     buf[1] = ebc64[addr%64];
  1056.     }
  1057. }
  1058.